package cn.virens.common.boot.rabbit.listener;

import cn.virens.common.boot.rabbit.RabbitMessage;
import cn.virens.common.util.exception.APIException;
import com.rabbitmq.client.Channel;
import lombok.Setter;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.springframework.amqp.core.Message;

import java.io.IOException;
import java.io.Serializable;

public abstract class AbstractRabbitReplyListener<T, R> extends AbstractRabbitListener<T> {
    @Override
    public void onMessage(Message inputMessage, Channel channel) throws IOException {
        RabbitMessage message = new RabbitMessage(inputMessage, channel);
        RabbitPacket packet = new RabbitPacket(message, getClazz());

        try {
            this.doPacketHandler(packet, message);
            this.sendReplySuccess(packet, message);
        } catch (Exception e) {
            this.sendReplyFailure(packet, message, e);
        } finally {
            IoUtil.closeQuietly(message);
        }
    }

    /**
     * 应答发送失败信息包
     */
    protected void sendReplyFailure(RabbitPacket packet, RabbitMessage message, Exception ex) throws IOException {
        if (StrUtil.isNotEmpty(message.getProperties().getReplyTo())) {
            this.doReply(buildReplyFailure(packet, ex), message);
        }

        logger.debug("消息处理失败：" + ex.getMessage(), ex);
    }

    /**
     * 应答发送成功信息包
     */
    protected void sendReplySuccess(RabbitPacket packet, RabbitMessage message) throws IOException {
        if (StrUtil.isNotEmpty(message.getProperties().getReplyTo())) {
            this.doReply(buildReplySuccess(packet), message);
        }
    }

    /**
     * 根据指令包生成对应的回复数据包(失败包)
     */
    protected abstract R buildReplyFailure(RabbitPacket packet, Exception ex) throws IOException;

    /**
     * 根据指令包生成对应的回复数据包(成功包)
     */
    protected abstract R buildReplySuccess(RabbitPacket packet) throws IOException;

    /**
     * 消息处理
     *
     * @param message 消息信息
     * @param pkt     消息包
     * @throws APIException
     */
    protected void doPacketHandler(RabbitPacket pkt, RabbitMessage message) throws IOException {
        this.onHandler(pkt.ctx(), message);
    }

    /**
     * 执行最后的应答操作
     */
    protected abstract void doReply(R reply, RabbitMessage message) throws IOException;

    @SuppressWarnings("serial")
    protected class RabbitPacket implements Serializable {
        private final long time;
        private final T ctx;

        @Setter
        private Object result;

        private RabbitPacket(RabbitMessage message, Class<T> clazz) {
            this.time = System.currentTimeMillis();
            this.ctx = message.getBody(clazz);
        }

        /**
         * 获取最后处理用时
         */
        public long getDuration() throws RuntimeException {
            return System.currentTimeMillis() - time;
        }

        public Object result() {
            return result;
        }

        public long time() {
            return time;
        }

        public T ctx() {
            return ctx;
        }
    }
}
